﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using ActivateYourGlutes.Infrastructure;
using ActivateYourGlutes.Model.Contracts;
using AutoMapper;

namespace ActivateYourGlutes.Model.Providers
{
    public class GoalProvider : ProviderBase, IGoalProvider
    {
        public GoalProvider(IEntityModelFactory factory) : base(factory)
        {

        }

        /// <summary>
        /// Returns the recently achieved goals for the given account
        /// </summary>
        public IEnumerable<Goal> RecentlyAchievedGoals(Account account)
        {
            return Mapper.Map<List<Internal.Goal>, List<Goal>>(Db.GoalSet.Include("MeasurementType")
                                                                    .Where(g => g.Account.AccountId == account.AccountId && g.AchievedOn != null)
                                                                    .OrderByDescending(g => g.AchievedOn)
                                                                    .Take(5)
                                                                    .ToList());
        }

        /// <summary>
        /// Returns all active goals for the account
        /// </summary>
        public IEnumerable<Goal> ActiveGoals(Account account)
        {
            return Mapper.Map<List<Internal.Goal>, List<Goal>>(
                Db.GoalSet.Include("MeasurementType")
                    .Where(g => g.Account.AccountId == account.AccountId && g.AchievedOn == null && g.Active)
                    .OrderByDescending(g => g.CreatedOn)
                    .ToList());
        }

        /// <summary>
        /// Add a goal
        /// </summary>
        public void Add(Goal goalToAdd, Account account, UserLocaleSettings settings)
        {
            var goal = new Internal.Goal();
            goal.TargetDate = goalToAdd.TargetDate;
            goal.TargetValue = goalToAdd.TargetValue;
            goal.AchievedOn = goalToAdd.AchievedOn;
            goal.Active = goalToAdd.Active;
            goal.DecreaseTo = goalToAdd.DecreaseTo;
            //goal.MeasurementTypeReference.EntityKey = new EntityKey("ActivateYourGlutesEntities.MeasurementTypeSet", "MeasurementTypeId", goalToAdd.MeasurementType.MeasurementTypeId);
            goal.MeasurementType = Db.MeasurementTypeSet.Where(mt => mt.MeasurementTypeId == goalToAdd.MeasurementType.MeasurementTypeId).First();
            goal.AccountReference.EntityKey = new EntityKey("ActivateYourGlutesEntities.Accounts", "AccountId", account.AccountId);
            goal.CreatedOn = DateTime.Now;

            var errors = goal.Validate();
            if (errors != null && errors.Count > 0)
                throw new ValidationException(errors);

            var activity = new Internal.Activity
                               {
                                   ActivityDate = goal.CreatedOn,
                                   Description = goalToAdd.ToString(settings),
                                   Title = "Set a new goal",
                                   AccountReference =
                                       {
                                           EntityKey =
                                               new EntityKey("ActivateYourGlutesEntities.Accounts", "AccountId",
                                                             account.AccountId)
                                       }
                               };
            Db.AddToActivitySet(activity);
            Db.AddToGoalSet(goal);
            Db.SaveChanges();
        }

        /// <summary>
        /// Returns a template goal that can be used as the basis for creating a new one
        /// </summary>
        public Goal Template(Account account)
        {
            var measurementType = account.PrimaryMeasurementType;
            if (account.PrimaryMeasurementType == null)
                measurementType = Mapper.Map<Internal.MeasurementType, MeasurementType>(Db.MeasurementTypeSet.First());

            return new Goal
                       {
                           AchievedOn = null,
                           Active = false,
                           CreatedOn = DateTime.Now,
                           DecreaseTo = true,                           
                           TargetValue = 0,
                           TargetDate = DateTime.Now.AddMonths(1),
                           MeasurementType = measurementType
                       };
        }

        /// <summary>
        /// Returns a goal based on an id
        /// </summary>
        public Goal GetGoalById(Account requestingAccount, int id)
        {
            var goal = Mapper.Map<Internal.Goal, Goal>(Db.GoalSet.Include("Account").Where(g => g.GoalId == id).FirstOrDefault());
            if (goal.Account.AccountId != requestingAccount.AccountId)
                throw new AuthorizationException("Attempt to view a goal that does not belong to the signed in user");
            return goal;
        }

        /// <summary>
        /// Deactivates the specified goal
        /// </summary>
        public void Deactivate(Account deactivatingAccount, Goal goalToDeactivate)
        {
            var goal = Db.GoalSet.Include("Account").Where(g => g.GoalId == goalToDeactivate.GoalId).First();
            if (goal.Account.AccountId != goal.Account.AccountId)
                throw new AuthorizationException("Attempt to deactivate a goal that does not belong to the signed in user");
            goal.Active = false;
            Db.SaveChanges();
        }
    }
}